<template>
  <view class="file-uploader">
    <view
      class="upload-btn"
      @click="handleUpload"
      v-if="imagesList.length < props.limit">
      上传图片
    </view>
    <view class="image-list">
      <view class="image-item" v-for="(item, index) in imagesList" :key="index">
        <image
          :src="completeImgPath(item)"
          :style="'width:100%;height:100%'"
          @click="handlePreviewImage(item)"></image>
        <view class="close-btn" @click="removeImage(item, index)">
          <uni-icons type="closeempty" size="24" color="#fff"></uni-icons>
        </view>
      </view>
    </view>
    <view class="preview-container" v-if="isPreview" @click="closePreview">
      <view class="preview-body">
        <image
          :src="previewImage"
          style="object-fit: contain; width: 100%; height: 100%"></image>
      </view>
    </view>
  </view>
</template>

<script setup lang="ts">
import { ref, watch, computed } from "vue";
import API from "@/api/index.js";
import { PropType } from "vue";
import { completeImgPath } from "@/utils/common.js";

const imagesList = ref<any>([]);
const isPreview = ref(false);
const previewImage = ref("");

// 组件属性定义
const props = defineProps({
  // 绑定值：字符串（单文件）或字符串数组（多文件）
  modelValue: {
    type: [String, Array] as PropType<string | string[]>,
    default: "",
  },
  // 最大上传数量
  limit: {
    type: Number,
    default: 1,
  },
  // 上传标题
  title: {
    type: String,
    default: "上传文件",
  },
});

// 组件事件
const emit = defineEmits(["update:modelValue", "upload-success"]);

// 预览文件
const handlePreviewImage = (url) => {
  previewImage.value = completeImgPath(url);
  isPreview.value = true;
};

// 关闭预览
const closePreview = () => {
  isPreview.value = false;
};

// 移除已上传的图片
const removeImage = async (path, index) => {
  if (imagesList.value[index]) {
    await API.tool.deleteFileByPathApi({ path });
    imagesList.value.splice(index, 1);
    // 通知父组件更新
    emit("update:modelValue", [...imagesList.value]);
    emit("upload-success", [...imagesList.value]);
  }
};

// 上传文件
const handleUpload = () => {
  uni.chooseImage({
    success: async (res) => {
      try {
        if (res.tempFilePaths && res.tempFilePaths.length > 0) {
          // 计算还能上传多少张
          const remaining = props.limit - imagesList.value.length;
          let list = res.tempFilePaths.slice(0, remaining);

          // 多文件上传处理
          const uploadPromises = list.map((filePath) => {
            return API.tool.uploadSingleApi({
              filePath,
            });
          });

          // 等待所有文件上传完成
          const results = await Promise.all(uploadPromises);
          for (const result of results) {
            if (result.success && result.data.filename) {
              imagesList.value.push(result.data.filename);
            }
          }

          // 通知父组件更新
          emit("update:modelValue", [...imagesList.value]);
          emit("upload-success", [...imagesList.value]);
        }
      } catch {
        uni.showToast({
          title: "上传失败",
          icon: "error",
        });
      }
    },
  });
};

// 监听 modelValue 变化，实现回显（添加防循环判断）
watch(
  () => props.modelValue,
  (newVal) => {
    // 只有新值与当前值不同时才更新，防止循环
    let currentValue = imagesList.value;
    if (Array.isArray(newVal)) {
      // 数组比较
      if (
        newVal.length !== currentValue.length ||
        newVal.some((val, idx) => val !== currentValue[idx])
      ) {
        imagesList.value = [...newVal];
      }
    } else if (newVal !== "" && newVal !== currentValue[0]) {
      // 单值比较
      imagesList.value = [newVal];
    } else if (newVal === "" && currentValue.length > 0) {
      imagesList.value = [];
    }
  },
  { immediate: true, deep: true }
);
</script>

<style lang="scss" scoped>
.file-uploader {
  .upload-btn {
    padding: 8px 0;
    text-align: center;
    background-color: #4cd964;
    color: #fff;
    border-radius: 4px;
    font-size: 14px;
    cursor: pointer;
  }
  .image-list {
    display: flex;
    flex-wrap: wrap;
    justify-content: flex-start;
    gap: 15px;
    margin-top: 15px;
    .image-item {
      width: 100px;
      height: 100px;
      border: 1px dashed #ddd;
      position: relative;
      .close-btn {
        background-color: #aaa;
        border-radius: 10px;
        position: absolute;
        top: -12px;
        right: -12px;
      }
    }
  }
  .preview-container {
    position: fixed;
    top: 0px;
    left: 0px;
    width: 100vw;
    height: 100vh;
    z-index: 100;
    background-color: rgba(0, 0, 0, 0.4);
    .preview-body {
      width: 100%;
      height: 100%;
      position: relative;
      display: flex;
      justify-content: center;
      align-items: center;
    }
  }
}
</style>
